package com.raizlabs.android.dbflow.structure.provider;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.database.Cursor;
import android.net.Uri;
import com.raizlabs.android.dbflow.annotation.provider.ContentProvider;
import com.raizlabs.android.dbflow.config.FlowLog;
import com.raizlabs.android.dbflow.config.FlowManager;
import com.raizlabs.android.dbflow.sql.language.Operator;
import com.raizlabs.android.dbflow.sql.language.OperatorGroup;
import com.raizlabs.android.dbflow.structure.ModelAdapter;
import com.raizlabs.android.dbflow.structure.database.FlowCursor;
import java.util.ArrayList;
import java.util.List;
/**
* Description: Provides handy wrapper mechanisms for {@link android.content.ContentProvider}
*/
public class ContentUtils {
/**
* The default content URI that Android recommends. Not necessary, however.
*/
public static final String BASE_CONTENT_URI = "content://";
/**
* Constructs an Uri with the {@link #BASE_CONTENT_URI} and authority. Add paths to append to the Uri.
*
* @param authority The authority for a {@link ContentProvider}
* @param paths The list of paths to append.
* @return A complete Uri for a {@link ContentProvider}
*/
public static Uri buildUriWithAuthority(String authority, String... paths) {
return buildUri(BASE_CONTENT_URI, authority, paths);
}
/**
* Constructs an Uri with the specified baseContent uri and authority. Add paths to append to the Uri.
*
* @param baseContentUri The base content URI for a {@link ContentProvider}
* @param authority The authority for a {@link ContentProvider}
* @param paths The list of paths to append.
* @return A complete Uri for a {@link ContentProvider}
*/
public static Uri buildUri(String baseContentUri, String authority, String... paths) {
Uri.Builder builder = Uri.parse(baseContentUri + authority).buildUpon();
for (String path : paths) {
builder.appendPath(path);
}
return builder.build();
}
/**
* Inserts the model into the {@link android.content.ContentResolver}. Uses the insertUri to resolve
* the reference and the model to convert its data into {@link android.content.ContentValues}
*
* @param insertUri A {@link android.net.Uri} from the {@link ContentProvider} class definition.
* @param model The model to insert.
* @return A Uri of the inserted data.
*/
public static <TableClass> Uri insert(Uri insertUri, TableClass model) {
return insert(FlowManager.getContext().getContentResolver(), insertUri, model);
}
/**
* Inserts the model into the {@link android.content.ContentResolver}. Uses the insertUri to resolve
* the reference and the model to convert its data into {@link android.content.ContentValues}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param insertUri A {@link android.net.Uri} from the {@link ContentProvider} class definition.
* @param model The model to insert.
* @return The Uri of the inserted data.
*/
@SuppressWarnings("unchecked")
public static <TableClass> Uri insert(ContentResolver contentResolver, Uri insertUri, TableClass model) {
ModelAdapter<TableClass> adapter = (ModelAdapter<TableClass>) FlowManager.getModelAdapter(model.getClass());
ContentValues contentValues = new ContentValues();
adapter.bindToInsertValues(contentValues, model);
Uri uri = contentResolver.insert(insertUri, contentValues);
adapter.updateAutoIncrement(model, Long.valueOf(uri.getPathSegments().get(uri.getPathSegments().size() - 1)));
return uri;
}
/**
* Inserts the list of model into the {@link ContentResolver}. Binds all of the models to {@link ContentValues}
* and runs the {@link ContentResolver#bulkInsert(Uri, ContentValues[])} method. Note: if any of these use
* autoIncrementing primary keys the ROWID will not be properly updated from this method. If you care
* use {@link #insert(ContentResolver, Uri, Object)} instead.
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param bulkInsertUri The URI to bulk insert with
* @param table The table to insert into
* @param models The models to insert.
* @return The count of the rows affected by the insert.
*/
public static <TableClass> int bulkInsert(ContentResolver contentResolver, Uri bulkInsertUri,
Class<TableClass> table, List<TableClass> models) {
ContentValues[] contentValues = new ContentValues[models == null ? 0 : models.size()];
ModelAdapter<TableClass> adapter = FlowManager.getModelAdapter(table);
if (models != null) {
for (int i = 0; i < contentValues.length; i++) {
contentValues[i] = new ContentValues();
adapter.bindToInsertValues(contentValues[i], models.get(i));
}
}
return contentResolver.bulkInsert(bulkInsertUri, contentValues);
}
/**
* Inserts the list of model into the {@link ContentResolver}. Binds all of the models to {@link ContentValues}
* and runs the {@link ContentResolver#bulkInsert(Uri, ContentValues[])} method. Note: if any of these use
* autoincrement primary keys the ROWID will not be properly updated from this method. If you care
* use {@link #insert(Uri, Object)} instead.
*
* @param bulkInsertUri The URI to bulk insert with
* @param table The table to insert into
* @param models The models to insert.
* @return The count of the rows affected by the insert.
*/
public static <TableClass> int bulkInsert(Uri bulkInsertUri, Class<TableClass> table, List<TableClass> models) {
return bulkInsert(FlowManager.getContext().getContentResolver(), bulkInsertUri, table, models);
}
/**
* Updates the model through the {@link android.content.ContentResolver}. Uses the updateUri to
* resolve the reference and the model to convert its data in {@link android.content.ContentValues}
*
* @param updateUri A {@link android.net.Uri} from the {@link ContentProvider}
* @param model A model to update
* @return The number of rows updated.
*/
public static <TableClass> int update(Uri updateUri, TableClass model) {
return update(FlowManager.getContext().getContentResolver(), updateUri, model);
}
/**
* Updates the model through the {@link android.content.ContentResolver}. Uses the updateUri to
* resolve the reference and the model to convert its data in {@link android.content.ContentValues}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param updateUri A {@link android.net.Uri} from the {@link ContentProvider}
* @param model The model to update
* @return The number of rows updated.
*/
@SuppressWarnings("unchecked")
public static <TableClass> int update(ContentResolver contentResolver, Uri updateUri, TableClass model) {
ModelAdapter<TableClass> adapter = (ModelAdapter<TableClass>) FlowManager.getModelAdapter(model.getClass());
ContentValues contentValues = new ContentValues();
adapter.bindToContentValues(contentValues, model);
int count = contentResolver.update(updateUri, contentValues, adapter.getPrimaryConditionClause(model).getQuery(), null);
if (count == 0) {
FlowLog.log(FlowLog.Level.W, "Updated failed of: " + model.getClass());
}
return count;
}
/**
* Deletes the specified model through the {@link android.content.ContentResolver}. Uses the deleteUri
* to resolve the reference and the model to {@link ModelAdapter#getPrimaryConditionClause(Object)}}
*
* @param deleteUri A {@link android.net.Uri} from the {@link ContentProvider}
* @param model The model to delete
* @return The number of rows deleted.
*/
@SuppressWarnings("unchecked")
public static <TableClass> int delete(Uri deleteUri, TableClass model) {
return delete(FlowManager.getContext().getContentResolver(), deleteUri, model);
}
/**
* Deletes the specified model through the {@link android.content.ContentResolver}. Uses the deleteUri
* to resolve the reference and the model to {@link ModelAdapter#getPrimaryConditionClause(Object)}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param deleteUri A {@link android.net.Uri} from the {@link ContentProvider}
* @param model The model to delete
* @return The number of rows deleted.
*/
@SuppressWarnings("unchecked")
public static <TableClass> int delete(ContentResolver contentResolver, Uri deleteUri, TableClass model) {
ModelAdapter<TableClass> adapter = (ModelAdapter<TableClass>) FlowManager.getModelAdapter(model.getClass());
int count = contentResolver.delete(deleteUri, adapter.getPrimaryConditionClause(model).getQuery(), null);
// reset autoincrement to 0
if (count > 0) {
adapter.updateAutoIncrement(model, 0);
} else {
FlowLog.log(FlowLog.Level.W, "A delete on " + model.getClass() + " within the ContentResolver appeared to fail.");
}
return count;
}
/**
* Queries the {@link android.content.ContentResolver} with the specified query uri. It generates
* the correct query and returns a {@link android.database.Cursor}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param queryUri The URI of the query
* @param whereConditions The set of {@link Operator} to query the content provider.
* @param orderBy The order by clause without the ORDER BY
* @param columns The list of columns to query.
* @return A {@link android.database.Cursor}
*/
public static Cursor query(ContentResolver contentResolver, Uri queryUri,
OperatorGroup whereConditions,
String orderBy, String... columns) {
return contentResolver.query(queryUri, columns, whereConditions.getQuery(), null, orderBy);
}
/**
* Queries the {@link android.content.ContentResolver} with the specified queryUri. It will generate
* the correct query and return a list of {@link TableClass}
*
* @param queryUri The URI of the query
* @param table The table to get from.
* @param whereConditions The set of {@link Operator} to query the content provider.
* @param orderBy The order by clause without the ORDER BY
* @param columns The list of columns to query.
* @return A list of {@link TableClass}
*/
public static <TableClass> List<TableClass> queryList(Uri queryUri, Class<TableClass> table,
OperatorGroup whereConditions,
String orderBy, String... columns) {
return queryList(FlowManager.getContext().getContentResolver(), queryUri, table, whereConditions, orderBy, columns);
}
/**
* Queries the {@link android.content.ContentResolver} with the specified queryUri. It will generate
* the correct query and return a list of {@link TableClass}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param queryUri The URI of the query
* @param table The table to get from.
* @param whereConditions The set of {@link Operator} to query the content provider.
* @param orderBy The order by clause without the ORDER BY
* @param columns The list of columns to query.
* @return A list of {@link TableClass}
*/
public static <TableClass> List<TableClass> queryList(ContentResolver contentResolver, Uri queryUri,
Class<TableClass> table,
OperatorGroup whereConditions,
String orderBy, String... columns) {
FlowCursor cursor = FlowCursor.from(contentResolver.query(queryUri, columns, whereConditions.getQuery(), null, orderBy));
if (cursor != null) {
return FlowManager.getModelAdapter(table)
.getListModelLoader()
.load(cursor);
}
return new ArrayList<>();
}
/**
* Queries the {@link android.content.ContentResolver} with the specified queryUri. It will generate
* the correct query and return a the first item from the list of {@link TableClass}
*
* @param queryUri The URI of the query
* @param table The table to get from
* @param whereConditions The set of {@link Operator} to query the content provider.
* @param orderBy The order by clause without the ORDER BY
* @param columns The list of columns to query.
* @return The first {@link TableClass} of the list query from the content provider.
*/
public static <TableClass> TableClass querySingle(Uri queryUri, Class<TableClass> table,
OperatorGroup whereConditions,
String orderBy, String... columns) {
return querySingle(FlowManager.getContext().getContentResolver(), queryUri, table, whereConditions, orderBy, columns);
}
/**
* Queries the {@link android.content.ContentResolver} with the specified queryUri. It will generate
* the correct query and return a the first item from the list of {@link TableClass}
*
* @param contentResolver The content resolver to use (if different from {@link FlowManager#getContext()})
* @param queryUri The URI of the query
* @param table The table to get from
* @param whereConditions The set of {@link Operator} to query the content provider.
* @param orderBy The order by clause without the ORDER BY
* @param columns The list of columns to query.
* @return The first {@link TableClass} of the list query from the content provider.
*/
public static <TableClass> TableClass querySingle(ContentResolver contentResolver, Uri queryUri, Class<TableClass> table,
OperatorGroup whereConditions,
String orderBy, String... columns) {
List<TableClass> list = queryList(contentResolver, queryUri, table, whereConditions, orderBy, columns);
return list.size() > 0 ? list.get(0) : null;
}
}